package cn.xmoit.sample.spring.security.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;

import javax.sql.DataSource;

/**
 * 注意：@Configuration 注解表示这是一个配置类，@Configuration 注解的配置类相当于一个 xml 配置文件
 *
 * @author fangyy
 */
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

	@Autowired
	private DataSource dataSource;

	@Bean
	public JdbcTokenRepositoryImpl jdbcTokenRepository() {
		JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
		jdbcTokenRepository.setDataSource(dataSource);
		return jdbcTokenRepository;
	}

	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception { // auth.inMemoryAuthentication()
		auth.inMemoryAuthentication()
			.withUser("admin")
			.password(bcryptPasswordEncoder().encode("123456"))
			.roles("ADMIN")
			.and()
			.withUser("user")
			.password(bcryptPasswordEncoder().encode("123456"))
			.roles("USER");
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http // 配置登录页并允许访问
			.formLogin()
			.usernameParameter("username")
			.passwordParameter("password")
			.loginPage("/login")
			.permitAll()
			// 配置Basic登录
			// .and().httpBasic()
			// 配置登出页面
			.and()
			.logout()
			.logoutUrl("/logout")
			.logoutSuccessUrl("/")
			// 开放接口访问权限，不需要登录授权就可以访问
			.and()
			.authorizeRequests()
			.antMatchers("/oauth/**", "/login/**", "/logout/**")
			.permitAll()
			// 需要 Remember Me 才能访问，先退出浏览器，再开启浏览器访问生效
			.antMatchers("/remember-me")
			.rememberMe()
			// fullyAuthenticated 不包含自动登录的形式。
			// 必须要用户名密码认证之后才能访问，如果用户是通过自动登录认证的，则必须重新输入用户名密码才能访问该接口。
			.antMatchers("/admin/**")
			.fullyAuthenticated()
			// api接口需要admin管理员才能访问
			.antMatchers("/api/**")
			.hasRole("ADMIN")
			// 其余所有请求全部需要鉴权认证
			.anyRequest()
			.authenticated()
			// 开启记住我功能，登陆成功以后，将cookie发给浏览器保存，以后访问页面带上这个cookie，只要通过检查就可以免登录
			.and()
			.rememberMe()
			.rememberMeParameter("remember-me")
			.key("demo")
			.tokenRepository(jdbcTokenRepository())

			// 关闭跨域保护;
			.and()
			.csrf()
			.disable();
	}

	/**
	 * 配置不拦截静态资源
	 * @param web
	 * @throws Exception
	 */
	@Override
	public void configure(WebSecurity web) throws Exception {
		// 解决静态资源被拦截的问题
		web.ignoring().antMatchers("/assets/**");
		web.ignoring().antMatchers("/favicon.ico");
	}

	@Bean
	public PasswordEncoder bcryptPasswordEncoder() {
		return new BCryptPasswordEncoder();
	}

}
